import logging
import socket
from event import ReadableHandler

log = logging
class Notifier(ReadableHandler):
    def __init__(self):
        (s, r) = socket.socketpair()
        self.__sender = s
        self.__receiver = r

        self.__sender.shutdown(socket.SHUT_RD)
        self.__receiver.shutdown(socket.SHUT_WR)

        self.__is_inited = True
        self.__identify = -1

    def __del__(self):
        self.close()

    def id(self):
        return self.__identify
    def set_id(self, identity):
        if self.__identify != identity:
            self.__identify = identity

    def fno(self):
        return self.__receiver

    def signal(self, cmd=b'e'):
        log.debug(f"notify->signal:[{cmd}]")
        if self.__is_inited:
            self.__sender.send(cmd)
        else:
            log.error("signal with uninited state")

    #TODO: think more about the buf_size??????
    def consume_signal(self, buf_size=1):
        if self.__is_inited:
            return self.__receiver.recv(buf_size)
        else:
            log.error("consume signal failed, uninited state")


    def close(self):
        if self.__is_inited:
            log.debug("notifier is closed:[{}]".format(self))
            self.__receiver.close()
            self.__sender.close()
            self.__is_inited = False


    #override from ReadableHandler
    def read(self, event):
        signals = self.consume_signal()
        log.debug(f"notify->consume_signal:[{signals}], notifier:[{self}]")


    def __str__(self):
        return "sender:{}, receiver:{}, inited:{}, id:{}".format(self.__sender.fileno(), self.__receiver.fileno(), self.__is_inited, self.__identify)

import unittest
import socket
import threading
class TestNotifier(unittest.TestCase):
    def test_main(self):
        n = Notifier()  
        print(f"{n}")

        class Waiter(threading.Thread):
            def __init__(self, n):
                self.__n = n
                super().__init__()
            def run(self):
                for i in range(2):
                    print("Waiting for an signal")
                    print(self.__n.consume_signal())
        
        thread = Waiter(n)
        thread.start()

        import time
        time.sleep(1)
        n.signal() 

        import time
        time.sleep(1)
        n.signal() 

        thread.join()

        n.close()

    #@unittest.skip('skip socket pair')
    def test_socket_pair(self):
        (sender, recver) = socket.socketpair()
        print(f"\ns1:{sender}\ns2:{recver}")
        sender.shutdown(socket.SHUT_RD)
        recver.shutdown(socket.SHUT_WR)
        

        
        sender.send(b'0')
        print(recver.recv(4))

        sender.close()
        recver.close()


if __name__ == "__main__":
    unittest.main(verbosity=2)
